//
//  自旋锁.h
//  Source
//
//  Created by Toj on 9/14/21.
//

自旋锁: OSSpinLock
推荐地址: https://blog.ibireme.com/2016/01/16/spinlock_is_unsafe_in_ios/

#pragma mark - 问题
1. 什么是自旋锁?
2. 自旋锁干什么的?
3. 自旋锁有什么缺点?
4. 自旋锁的应用?
5. 底层实现

#pragma mark - 什么是自旋锁
自旋锁: 在短期间内进行轻量级的锁定
它是为实现保护共享资源而提出一种锁机制,
自旋锁与互斥锁比较类似, 它们都是为了解决对某项资源的互斥使用.
无论是互斥锁, 还是自旋锁, 在任何时刻, 在任何时刻最多只能有一个执行单元获得锁.
但是两者在调度机制上略有不同.
互斥锁: 如果资源已经被占用, 资源申请者只能进入睡眠状态.
自旋锁: 不会引起调用者睡眠, 自旋锁已经被别的执行单元保持, 调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,
"自旋"一词就是因此而得名

#pragma mark - 自旋锁干什么的?
自旋锁是专为防止多处理器并发而引入的一种锁, 它在内核中大量应用于中断处理等部分
(对于单处理器来说,
 防止中断处理中的并发可简单采用关闭中断的方
 式, 即在标志寄存器中关闭/打开中断标志位，不需要自旋锁)
当访问的一块资源被锁的时候, 当前线程会一直保持等待状态, 不会睡眠, 会一直循环在哪里看是否自旋锁保持已经解锁.
* 就因为长时间等待所以是很耗资源的. 利用于锁比较短的时间内的情况,

#pragma makr - 自旋锁有什么缺点
* 它是不安全的线程锁:
如果一个低优先级的线程获得锁并访问共享资源,
这时一个高优先级的线程也尝试获得这个锁,
它会处于 spin lock 的忙等状态从而占用大量 CPU.
此时低优先级线程无法与高优先级线程争夺 CPU 时间, 从而导致任务迟迟完不成、无法释放 lock.

OSSpinLock: 缺点：可能出现优先级反转 已经不再安全 苹果也不推荐使用

* 解决办法:
1. 解决办法: truly unbounded backoff 算法
可是负载比较高的时候, 会堵塞现成10秒左右.

2. 解决办法: 使用 handoff lock 算法，这也是 libobjc 目前正在使用的
锁的持有者会把线程 ID 保存到锁内部, 锁的等待者会临时贡献出它的优先级来避免优先级反转的问题.
理论上这种模式会在比较复杂的多锁条件下产生问题, 但实践上目前还一切都好
libobjc 里用的是 Mach 内核的 thread_switch() 然后传递了一个 mach thread port 来避免优先级反转,
另外它还用了一个私有的参数选项, 所以开发者无法自己实现这个锁.
另一方面, 由于二进制兼容问题, OSSpinLock 也不能有改动

可以用 os_unfair_lock替换

#pragma makr - 自旋锁的应用?
应用案例: atomic 底层内就是用自旋锁实现
spin_lock(&mr_lock);
//临界区
spin_unlock(&mr_lock);

#pragma makr - 底层实现

do{
    b=1;
    while(b){
        lock(bus);
        b = test_and_set(&lock);
        unlock(bus);
    }
    临界区
    lock = 0;
    其余部分
}while(1)
